#include <sstream>
#include <unistd.h>
#include <netinet/in.h>

#include <rtc_base/logging.h>
#include <rtc_base/crc32.h>
#include <rtc_base/string_encode.h>


#include "base/socket.h"
#include "udp_port.h"
#include "ice/ice_connection.h"

namespace xrtc {

/*
    Foundation 是一个字符串标识符，用于：
​    ​分组相关候选地址​​：同一网络路径的候选地址共享相同的 foundation (相同 Foundation = 相同网络路径)
​    ​优化连通性检查​​：避免对相同路径的候选地址重复检查
​    ​标识网络拓扑​​：识别来自相同网络接口的候选地址
*/
// 计算 ICE 候选地址的 ​​foundation（基础标识）    
std::string compute_foundation(
    const std::string& type,             // 候选地址类型：host/srflx/relay
    const std::string& protocol,         // 传输协议：udp/tcp
    const std::string& relay_protocol,   // 中继协议（仅relay类型有效）
    const rtc::SocketAddress& base)      // 基础地址
{
    // 1. 创建唯一标识字符串
    std::stringstream ss;
    ss << type                     // 候选类型
       << base.HostAsURIString()   // 基础地址的IP（URI编码）
       << protocol                 // 传输协议
       << relay_protocol;          // 中继协议
    
    // 2. 计算CRC32校验和
    return std::to_string(rtc::ComputeCrc32(ss.str()));
}

UDPPort::UDPPort(EventLoop *el, const std::string &transport_name,      
                 IceCandidateComponent component, IceParameters ice_params) 
                : m_el(el), m_transport_name(transport_name), 
                  m_component(component), m_ice_params(ice_params) {

    
}

UDPPort::~UDPPort() {
    if (m_socket >= 0) {
        close(m_socket);
        m_socket = -1;
    }
}

// 创建Candidate
int UDPPort::create_ice_candidate(Network *network, int min_port, int max_port, Candidate &c)
{
    m_socket = create_udp_socket(network->getIP().family());
    if (m_socket < 0)  {
        return -1;
    }

    if (sock_setnonblock(m_socket) < 0) {
        return -1;
    }

    // 检查是否为NAT环境（硬编码的公网IP）
    bool is_nat_environment = (network->getName() == "fallback_public");
    
    sockaddr_in addr_in;
    addr_in.sin_family = network->getIP().family();
    
    if (is_nat_environment) {
        // NAT环境：绑定到0.0.0.0，让系统自动选择本地网卡
        addr_in.sin_addr.s_addr = INADDR_ANY;
        RTC_LOG(LS_INFO) << "NAT environment detected, binding to INADDR_ANY";
    } else {
        // 正常环境：绑定到指定的网络接口IP
        addr_in.sin_addr = network->getIP().ipv4_address();
        RTC_LOG(LS_INFO) << "Normal environment, binding to: " << network->getIP().ToString();
    }

    if (sock_bind(m_socket, (struct sockaddr*)&addr_in, sizeof(sockaddr), min_port, max_port) != 0) {
        RTC_LOG(LS_ERROR) << "Failed to bind socket, error: " << strerror(errno);
        return -1;
    }

    int port = 0;
    if (sock_get_address(m_socket, nullptr, &port) != 0) {
        return -1;
    }

    // 获取实际绑定的本地地址
    rtc::SocketAddress actual_local_addr;
    if (sock_get_local_address(m_socket, &actual_local_addr) != 0) {
        RTC_LOG(LS_WARNING) << "Failed to get local address, using fallback";
        rtc::IPAddress fallback_ip;
        if (rtc::IPFromString("0.0.0.0", &fallback_ip)) {
            actual_local_addr.SetIP(fallback_ip);
        } else {
            actual_local_addr.SetIP(rtc::IPAddress(INADDR_ANY));
        }
        actual_local_addr.SetPort(port);
    }

    // 保存实际绑定的本地地址
    m_local_addr = actual_local_addr;

    m_async_socket = std::make_unique<AsyncUdpSocket>(m_el, m_socket);
    // 连接AsyncUdpSocket::signal_read_packet信号到UDPPort::_on_read_packet方法
    m_async_socket->signal_read_packet.connect(this, &UDPPort::_on_read_packet);

    RTC_LOG(LS_INFO) << "Socket bound successfully - Local: " << m_local_addr.ToString() 
                     << ", Candidate IP: " << network->getIP().ToString();

    c.m_component = m_component;
    c.m_protocol = "udp";
    // 候选地址使用网络配置的IP（可能是NAT映射的公网IP）
    c.m_address = rtc::SocketAddress(network->getIP(), port);
    c.m_port = port;
    c.m_username = m_ice_params.m_ice_ufrag;
    c.m_password = m_ice_params.m_ice_pwd;
    
    // 根据环境设置candidate类型和优先级
    if (is_nat_environment) {
        // NAT环境：使用srflx类型（server-reflexive candidate）
        c.m_type = "srflx";
        c.m_priority = c.get_priority(ICE_TYPE_PREFERENCE_SRFLX, 0, 0);
        RTC_LOG(LS_INFO) << "Created srflx candidate for NAT environment";
    } else {
        // 正常环境：使用host类型
        c.m_type = LOCAL_PORT_TYPE;
        c.m_priority = c.get_priority(ICE_TYPE_PREFERENCE_HOST, 0, 0);
        RTC_LOG(LS_INFO) << "Created host candidate for normal environment";
    }
    
    c.m_foundation = compute_foundation(c.m_type, c.m_protocol, "", c.m_address);

    m_candidates.push_back(c);

    return 0;
}

// 从UDP数据包中提取STUN消息，并调用StunMessage::validate_fingerprint()验证
bool UDPPort::get_stun_message(const char *data, size_t len, const rtc::SocketAddress& addr,
                                std::unique_ptr<StunMessage> *out_msg, std::string& out_username)
{
    // 1. 验证STUN消息的Fingerprint属性
    if (!StunMessage::validate_fingerprint(data, len)) {
        return false;
    }

    out_username.clear();

    std::unique_ptr<StunMessage> stun_msg = std::make_unique<StunMessage>();
    rtc::ByteBufferReader buf(data, len);
    if (!stun_msg->read_from(&buf) || buf.Length() != 0) {
        return false;
    }

    // 2. 验证STUN消息的类型
    if (stun_msg->getMessageType() == STUN_BINDING_REQUEST) {
        // 2.1 验证STUN消息的属性
        if (!stun_msg->get_byte_string_attribute(STUN_ATTR_USERNAME) || 
            !stun_msg->get_byte_string_attribute(STUN_ATTR_MESSAGE_INTEGRITY)) {
            RTC_LOG(LS_WARNING) << to_string() << ": recevied "
                                << stun_method_to_string(stun_msg->getMessageType()) 
                                << " without username/M-I from "
                                << addr.ToString();
            // 返回错误的请求响应
            send_binding_error_response(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST, STUN_ERROR_REASON_BAD_REQUEST);
            return true;
        }

        // 2.2 解析并验证STUN消息的USERNAME属性
        std::string local_ufrag;
        std::string remote_ufrag;
        if (!_parse_stun_username(stun_msg.get(), local_ufrag, remote_ufrag) || 
            local_ufrag != m_ice_params.m_ice_ufrag) {
            RTC_LOG(LS_WARNING) << to_string() << ": recevied "
                << stun_method_to_string(stun_msg->getMessageType()) 
                << " with bad local_ufrag: " << local_ufrag
                << " from " << addr.ToString();
            
            // 返回未授权的错误响应
            send_binding_error_response(stun_msg.get(), addr, STUN_ERROR_UNATHORIZED,STUN_ERROR_REASON_UNATHORIZED);    

            return true;
        }
        
        // 2.3 验证STUN消息的MESSAGE-INTEGRITY属性
        if (stun_msg->validate_message_integrity(m_ice_params.m_ice_pwd) != StunMessage::MessageIntegrityStatus::k_integrity_ok) {
            RTC_LOG(LS_WARNING) << to_string() << ": recevied "
                << stun_method_to_string(stun_msg->getMessageType()) 
                << " with bad M-I from "
                << addr.ToString();
            
            // 返回未授权的错误响应
            send_binding_error_response(stun_msg.get(), addr, STUN_ERROR_UNATHORIZED, STUN_ERROR_REASON_UNATHORIZED);    
            
            return true;
        }

        out_username = remote_ufrag;
    }

    *out_msg = std::move(stun_msg);

    return true;
}

std::string UDPPort::to_string()
{
    std::stringstream ss;
    ss << "Port[" << this << ":" << m_transport_name 
                          << ":" << m_component 
                          << ":" << m_ice_params.m_ice_ufrag 
                          << ":" << m_ice_params.m_ice_pwd 
                          << ":" << m_local_addr.ToString()
                          << "]";
    return ss.str();
}


// 创建IceConnection对象
IceConnection *UDPPort::create_connection(const Candidate &remote_candidate) {
    // TODO
    IceConnection *ice_connection = new IceConnection(m_el, this, remote_candidate);
    auto ret = m_connections.insert(std::make_pair(ice_connection->get_remote_candidate().m_address, ice_connection));
    if (ret.second == false && ret.first->second != ice_connection) {
        RTC_LOG(LS_WARNING) << to_string() << ": create ice connection on "
            << "an existing remote address, addr: " 
            << ice_connection->get_remote_candidate().m_address.ToString();

        // TODO
        ret.first->second = ice_connection;
    }

    return ice_connection;
}

// 获取IceConnection对象
IceConnection *UDPPort::get_connection(const rtc::SocketAddress &addr) const {
    auto it = m_connections.find(addr);
    if (it != m_connections.end()) {
        return it->second;
    }
    return nullptr;
}

// 发送Binding错误响应
void UDPPort::send_binding_error_response(StunMessage *stun_msg, const rtc::SocketAddress &addr, 
                                          int err_code, const std::string &reason) {
    // TODO
}

int UDPPort::send_to(const char *buf, size_t len, const rtc::SocketAddress &addr) {
    if (!m_async_socket) {
        return -1;
    }

    return m_async_socket->send_to(buf, len, addr);
}

// 处理由AsyncUdpSocket::recv_data()发出的信号，接收Binding请求数据包
void UDPPort::_on_read_packet(AsyncUdpSocket *socket, char *buf, size_t size, 
                              const rtc::SocketAddress &addr, int64_t ts) {
    // 创建IceConnection对象
    IceConnection* ice_connection = get_connection(addr);
    if (ice_connection) {
        // 已经通过address创建了ice connection，直接在ice connection中处理数据包
        ice_connection->on_read_packet(buf, size, ts);
        return;
    }  

    // TODO
    std::unique_ptr<StunMessage> stun_msg;
    std::string remote_ufrag;
    bool res = get_stun_message(buf, size, addr, &stun_msg, remote_ufrag);
    if (!res || !stun_msg)  {
        return;
    }
    

    
    if (stun_msg->getMessageType() == STUN_BINDING_REQUEST) {
        // 处理Binding请求消息成功
        RTC_LOG(LS_WARNING) << to_string() << ": recevied "
                            << stun_method_to_string(stun_msg->getMessageType()) 
                            << " id = " << rtc::hex_encode(stun_msg->get_transaction_id())
                            << " from " << addr.ToString();

        // 在进行连通性检测时，发送未知地址（客户端NAT映射的反射地址）信号给传输通道
        signal_unknown_address(this, addr, stun_msg.get(), remote_ufrag);
    }
}

// 解析STUN消息的USERNAME属性
bool UDPPort::_parse_stun_username(StunMessage *stun_msg, std::string &local_ufrag, std::string &remote_ufrag) {
    local_ufrag.clear();
    remote_ufrag.clear();

    const StunByteStringAttribute *username_attr = stun_msg->get_byte_string_attribute(STUN_ATTR_USERNAME);
    if (!username_attr) {
        return false;
    }

    // RFRAG:LFRAG
    std::string username = username_attr->get_string();
    std::vector<std::string> fields;
    rtc::split(username, ':', &fields);
    if (fields.size() != 2) {
        return false;
    }

    local_ufrag = fields[0];
    remote_ufrag = fields[1];
    
    return true;
}

} // namespace xrtc
